#include <QVariant>
#include <QDebug>
#include "engine.h"
#include "mapsearchnode.h"
#include "astarsearch.h"

Engine::Engine(QObject *parent) :
    QObject(parent)
{
    m_search_ongoing = false;
}

bool Engine::searching() {
    return m_search_ongoing;
}

int Engine::nodeValue(int row, int column) {
    int index = row*m_column_count + column;
    if (index >= m_map.count() || index < 0) {
        qCritical()<<"nodeValue()"<<row<<" "<<column<<"is out of index"<<m_map.count();
        return 9;
    }

    return m_map[index].toInt();
}

bool Engine::neighborNodes(const AStarSearchNode& currentNode,
                           QList<AStarSearchNode*>& neighbors) {
    const MapSearchNode *node = static_cast<const MapSearchNode*>(&currentNode);
    if (node) {
        int row = node->row();
        int column = node->column();
        //only check 4 directions
        int nodePosition[4][2] = {
            {row-1, column},
            {row, column-1},
            {row+1, column},
            {row, column+1}
        };
        for (int i = 0; i < 4; i++) {
            if (nodePosition[i][0] >=0 && nodePosition[i][0] <m_row_count  &&
                    nodePosition[i][1] >=0 && nodePosition[i][1] < m_column_count &&
                    m_map[index(nodePosition[i][0], nodePosition[i][1])].toInt() != 1) {
                neighbors.append(new MapSearchNode(this, nodePosition[i][0], nodePosition[i][1]));
            }
        }
    }
    return true;
}


QVariant Engine::findPath(QVariant map, int rowCount, int columnCount,
                          int startRow, int startColumn,
                          int endRow, int endColumn) {
    QList<QVariant> pathList;
    if (m_search_ongoing) {
        qDebug()<<"Search is ongoing, could not search again";
        return QVariant::fromValue(pathList);
    }

    m_search_ongoing = true;
    emit searchingChanged();

    m_map = map.toList();
    m_row_count = rowCount;
    m_column_count = columnCount;

    // Create a start node
    MapSearchNode nodeStart(this, startRow, startColumn);

    // Define the goal node
    MapSearchNode nodeEnd(this, endRow, endColumn);

    QList<AStarSearchNode*> path;
    AStarSearch astarsearch;
    astarsearch.search(nodeStart, nodeEnd, path);
    for (int i = 0; i < path.count(); i++) {
        MapSearchNode *node = static_cast<MapSearchNode*>(path[i]);
        if (node) {
            pathList.append(index(node->row(), node->column()));
        }
    }
    m_search_ongoing = false;
    emit searchingChanged();
    return QVariant::fromValue(pathList);
}

int Engine::index(int row, int column) {
    return row*m_column_count + column;
}
